/**
 *  @file SSLSocket.h
 */
#ifndef _SSLSOCKET_H_
#define _SSLSOCKET_H_

#include "../Socket.h"
#include "SSLContext.h"

namespace cppflib
{

class CFString;

namespace security { namespace cert { class X509Certificate; } }

namespace net
{

namespace ssl
{

/**
 *  Client SSL socket
 */
class _DLLAPI SSLSocket : public Socket
{
private:
    ptrany_t sslObj;
    ISSLPeerCertCallback *pPeerCertCb;

private:
    SSLSocket();
    explicit SSLSocket(Socket::sockattr_t verifyFlag);
    
private:
    virtual bool Create(const CFString &socketAddress, u16_t socketPort, Socket::SocketType socketType);
    virtual bool Accept(Socket &connectedSocket);
    virtual Socket * Accept();
    virtual bool Listen(int connectionBacklog);
    virtual int ReceiveFrom(u8_t * pBuf, int bufLen, int nFlags, CFString &peerAddress, u16_t &peerPort);
    virtual int ReceiveFromTimeout(int timeout, u8_t * pBuf, int bufLen, int nFlags, CFString &peerAddress, u16_t &peerPort);
    virtual int SendTo(const u8_t * pBuf, int bufLen, int nFlags, const CFString &peerAddress, u16_t peerPort);

private:
    void Initialize(ptrany_t sslObj, ISSLPeerCertCallback *pPeerCertCb, bool isServer);
    bool PostInitSSLObj();
    bool PostConnectionCheck(void);
    bool CheckSSLBlockingIOError(int &sslCallRet);
    bool CheckSSLNonBlockingIOError(int timeout, int &sslCallRet);
    void SetTargetHost(const CFString & targetHost);
    
public:    
    virtual ~SSLSocket(void);

    bool Create(const CFString &socketAddress, u16_t socketPort);
    virtual bool Connect(const CFString &hostAddress, u16_t hostPort);
    virtual bool Connect(const CFString &hostAddress, u16_t hostPort, int timeout);
    virtual int Receive(u8_t * pBuf, int bufLen, int nFlags);
    virtual int ReceiveTimeout(int timeout, u8_t * pBuf, int bufLen, int nFlags);
    virtual int Send(const u8_t * pBuf, int bufLen, int nFlags);
    virtual void Close();
    virtual void SetAttribute(sockattr_t attr, const BaseObject &val);

    void WaitHandshake(int timeout);
    bool Renegotiate(bool isWaitPeer, int timeout, bool needPeerAuth);
    security::cert::X509Certificate *GetPeerCertificate();
    
    friend class SSLContext;
    friend class SSLServerSocket;
};

} // end of namespace ssl

} // end of namespace net

} // end of namespace cppflib

#endif
